package cn.edu.tju.ldj.cashup.utils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import cn.edu.tju.ldj.cashup.constant.Constant;
import cn.edu.tju.ldj.cashup.webfetcher.CCBFetcherImpl;
import cn.edu.tju.ldj.cashup.webfetcher.ICCBFetcher;
import cn.edu.tju.ldj.cashup.mailer.Mailer;

public class RuserPlatin {
	
	public static boolean isDebug = false;
	public static boolean isRefreshData = false;
	public static ICCBFetcher fetcher = new CCBFetcherImpl();
	public static List<Map<String, Object>> silverList = new ArrayList<Map<String,Object>>();
	public static List<Map<String, Object>> goldenList = new ArrayList<Map<String,Object>>();
	public static List<Map<String, Object>> platinList = new ArrayList<Map<String,Object>>();
	public static Double silverNewPrice = 0.0;
	public static Double goldenNewPrice = 0.0;
	public static Double platinNewPrice = 0.0;
	
	private static int observeDateNum = 31;
	private static int fiveTenIndex = 365;
	private static int fiveTwnIndex = 365;
	private static int tenTwnIndex = 365;
	@SuppressWarnings("unused")
	private static final int STAT_INIT = -1, STAT_RISE = 0, STAT_WAVE = 1, STAT_FALL = 2;
	private static final int POSITION_INIT = 0, POSITION_BUY_LIT = 1, POSITION_BUY_MID = 2, 
	POSITION_BUY_HAV = 3, POSITION_SEL_LIT = -1, POSITION_SEL_MID = -2, POSITION_SEL_HAV = -3;
	private static final int WINDOW_INDEX = 8;
	@SuppressWarnings("unused")
	private static int curState = STAT_INIT;
	private static int curPosition = POSITION_INIT;
	private static int shortTermStat = STAT_INIT;
	private static int midTermStat = STAT_INIT;
	private static int longTermStat = STAT_INIT;
	
	private static int tradeHands = 0;     //开仓手数
	private static Double capital = 0.0;
	private static Double capitalShadow = 0.0;
//	private static Double rewards = 0.0;
//	private static Double leverage = 6.0;
	public static Double gapThreshold = 0.036;
	public static Double gapNDayThreshold = 0.036;
	public static List<String> orderList = new ArrayList<String>();
	/**
	 * @param args
	 */
	
	public static void initDayAvgPrices(){
		if(platinList.size() < WINDOW_INDEX || isRefreshData){
			platinList = fetcher.getDayAvgData(Constant.platinAvgUrl);
			silverList = fetcher.getDayAvgData(Constant.silverAvgUrl);
			isRefreshData = false;
		}
//		goldenList = fetcher.getDayAvgData(Constant.goldenAvgUrl);
//		platinList = fetcher.getDayAvgData(Constant.platinAvgUrl);
	}
	
	public static void getNewPrices(){
//		silverNewPrice = (Double)platinList.get(platinList.size()-1).get("close"); //for test
		System.out.println("-+-+-+-+当前日期："+platinList.get(platinList.size()-1).get("time"));
		if(!isDebug){
			silverNewPrice = fetcher.getNewPrice(Constant.silverNewPriceUrl);
		}
//		goldenNewPrice = fetcher.getNewPrice(Constant.goldenNewPriceUrl);
//		platinNewPrice = fetcher.getNewPrice(Constant.platinNewPriceUrl);
	}
	
	public static void getStrategy(){
		initDayAvgPrices();
		initBehaviors();
		orderList.clear();
		getNewPrices();
		getAvglineState();
		getWhereWeAre();
		informBoss();
		refreshBehaviors();
	}
	
	public static void getAvglineState(){
		int flag = 0;
		int dice = 0;
		for (int i = platinList.size()-1; i > (platinList.size() - observeDateNum - 1) && i > 0 ; i--) {
			if((Double)platinList.get(i).get("TWENDAYAVG") - (Double)platinList.get(i).get("TENDAYAVG") > 0){
				dice = 1;
			}else{
				dice = -1;
			}
			if(flag == 0){
				flag = dice;
				tenTwnIndex = 1;
			}else if(flag == dice){
				++tenTwnIndex;
			}else if(flag != dice){
				--tenTwnIndex;
//				System.out.println(platinList.get(i+1).get("time") + "  tenTwnIndex="+tenTwnIndex + " lastItem="+(platinList.size()-1) + " i="+i);
				break;
			}
		}
		if (flag == 1) {
			longTermStat = STAT_FALL;
//			System.out.println("fall");
		} else if (flag == -1) {
			longTermStat = STAT_RISE;
//			System.out.println("rise");
		}
		
		flag = 0;
		dice = 0;
		for (int i = platinList.size()-1; i > (platinList.size() - observeDateNum - 1) && i > 0 ; i--) {
			if((Double)platinList.get(i).get("TWENDAYAVG") - (Double)platinList.get(i).get("FIVEDAYAVG") > 0){
				dice = 1;
			}else{
				dice = -1;
			}
			if(flag == 0){
				flag = dice;
				fiveTwnIndex = 1;
			}else if(flag == dice){
				++fiveTwnIndex;
			}else if(flag != dice){
				--fiveTwnIndex;
//				System.out.println(platinList.get(i+1).get("time") + "  fiveTwnIndex="+fiveTwnIndex + " lastItem="+(platinList.size()-1) + " i="+i);
				break;
			}
		}
		if (flag == 1) {
			midTermStat = STAT_FALL;
//			System.out.println("fall");
		} else if (flag == -1) {
			midTermStat = STAT_RISE;
//			System.out.println("rise");
		}
		
		flag = 0;
		dice = 0;
		for (int i = platinList.size()-1; i > (platinList.size() - observeDateNum - 1) && i > 0 ; i--) {
			if((Double)platinList.get(i).get("TENDAYAVG") - (Double)platinList.get(i).get("FIVEDAYAVG") > 0){
				dice = 1;
			}else{
				dice = -1;
			}
			if(flag == 0){
				flag = dice;
				fiveTenIndex = 1;
			}else if(flag == dice){
				++fiveTenIndex;
			}else if(flag != dice){
				--fiveTenIndex;
//				System.out.println(platinList.get(i+1).get("time") + "  fiveTenIndex="+fiveTenIndex + " lastItem="+(platinList.size()-1) + " i="+i);
				break;
			}
		}
		if (flag == 1) {
			shortTermStat = STAT_FALL;
//			System.out.println("fall");
		} else if (flag == -1) {
			shortTermStat = STAT_RISE;
//			System.out.println("rise");
		}
	}
	
	public static void getWhereWeAre(){
		
		if(longTermStat == STAT_FALL){
			if(midTermStat == STAT_FALL){//长期趋势为跌
				if(shortTermStat == STAT_FALL){ //蓝红黄  当前处于跌势 重空
					curState = STAT_FALL;System.out.println("当前下行中当前下行中当前下行中-------------------");
					if(tenTwnIndex <= fiveTenIndex && tenTwnIndex <= fiveTwnIndex){//当前下行中
						if(tenTwnIndex <= WINDOW_INDEX && isProceedGap()){ //开空仓窗口 这里暂时不理会当前价格
							getWhatToDo(POSITION_SEL_HAV);System.out.println("开空仓窗口 这里暂时不理会当前价格");
						}
						if(isTriRise()){//空仓中三日纯涨，为买入减仓信号，持中空仓
							getWhatToDo(POSITION_SEL_MID);System.out.println("去交叉空仓中三日纯涨，为买入减仓信号，持中空仓");
						}
					}else{
						if(isTriRise()){//空仓中三日纯涨，为买入减仓信号，持中空仓
							getWhatToDo(POSITION_SEL_LIT);System.out.println("去交叉空仓中三日纯涨，为买入减仓信号，持中空仓");
						}
						else if(isProceedGap() && tenTwnIndex <= WINDOW_INDEX){//确定的开空信号，重仓
							getWhatToDo(POSITION_SEL_HAV);System.out.println("蓝红黄, 确定的开空信号，重仓");
						}
					}
				}else if(shortTermStat == STAT_RISE){ //蓝黄红  轻多
					if(isTriRise()){//空仓中三日纯涨，为买入减仓信号，持轻空仓
						getWhatToDo(POSITION_SEL_MID);System.out.println("空仓中三日纯涨，为买入减仓信号，持轻空仓");
					}
					if(!isProceedGap()){
						if(isTwiTriUpAvgTwn() && curPosition < 0){//前三日有两日突破廿日均线，平仓
							getWhatToDo(POSITION_INIT);System.out.println("前三日有两日突破廿日均线，平仓");
						}
					}else{
						if(isTwiTriUpAvgTwn()){//前三日有两日突破廿日均线，平空仓信号，持轻多仓
							getWhatToDo(POSITION_BUY_LIT);System.out.println("前三日有两日突破廿日均线，平空仓信号，持轻多仓");
						}
					}
				}
			}else if(midTermStat == STAT_RISE){// 黄蓝红 中多
				if(shortTermStat == STAT_RISE){
					if(isObveTwnAvg() && isProceedGap(WINDOW_INDEX/2)){//前两交易均日收于蓝线上方，为买入加仓信号，持中多仓
						getWhatToDo(POSITION_BUY_MID);System.out.println("前两交易均日收于蓝线上方，为买入加仓信号，持中多仓");
					}
					if(isTwiFall() && curPosition > 0){
						getWhatToDo(POSITION_INIT);
					}
				}
			}
		}else if(longTermStat == STAT_RISE){ //长期趋势为涨
			if(midTermStat == STAT_FALL){
				if(shortTermStat == STAT_FALL){ //红蓝黄  开始下跌信号，中空
					curState = STAT_FALL;
					if(isProceedGap() && isProceedGap(WINDOW_INDEX/2) ){
						getWhatToDo(POSITION_SEL_MID);System.out.println("红蓝黄  开始下跌信号，中空");
					}
				}
			}else if(midTermStat == STAT_RISE){// 中期涨势
				if(shortTermStat == STAT_RISE){ //黄红蓝  纯涨 重多仓
					if (tenTwnIndex <= WINDOW_INDEX && isProceedGap()) { // 开多仓窗口
						getWhatToDo(POSITION_BUY_HAV);
						System.out.println("开多仓窗口 这里暂时不理会当前价格");
					}
					if(isTwiFall()){
						getWhatToDo(POSITION_BUY_LIT);System.out.println("开多仓窗口 前日连跌两日，减仓");
					}
				}else if(shortTermStat == STAT_FALL){//红黄蓝  涨势结束，平多仓信号
					if(curPosition > 0){
						getWhatToDo(POSITION_INIT);System.out.println("红黄蓝  涨势结束，平多仓信号");
					}
					
				}
			}
		}
	}
	
	public static boolean isProceedGap(){
		double fivAvg = (Double)platinList.get(platinList.size()-1).get("FIVEDAYAVG");
		double tenAvg = (Double)platinList.get(platinList.size()-1).get("TENDAYAVG");
		double twnAvg = (Double)platinList.get(platinList.size()-1).get("TWENDAYAVG");
		double gap = Math.abs(twnAvg - tenAvg) + Math.abs(twnAvg - fivAvg) + Math.abs(fivAvg - tenAvg);
		return gap > gapThreshold?true:false;
	}
	
	public static boolean isProceedGap(int dayNum){
		double gap = 0.0;
		for (int i = 0; i < dayNum; i++) {
			double fivAvg = (Double)platinList.get(platinList.size()-1-i).get("FIVEDAYAVG");
			double tenAvg = (Double)platinList.get(platinList.size()-1-i).get("TENDAYAVG");
			double twnAvg = (Double)platinList.get(platinList.size()-1-i).get("TWENDAYAVG");
			gap += Math.abs(twnAvg - tenAvg) + Math.abs(twnAvg - fivAvg) + Math.abs(fivAvg - tenAvg);
		}
		gap = gap/dayNum;
		return gap > gapNDayThreshold?true:false;
	}
	
	public static void initBehaviors(){
		if(Math.abs(capital) > 0.1){
			return;
		}
		try {
			String encoding = "UTF8";
			File file = new File("data.txt");
			if (file.isFile() && file.exists()) { // 判断文件是否存在
				InputStreamReader read = new InputStreamReader(
						new FileInputStream(file), encoding);// 考虑到编码格式
				BufferedReader bufferedReader = new BufferedReader(read);
				String lineTxt = null;
				while ((lineTxt = bufferedReader.readLine()) != null) {
					tradeHands = Integer.valueOf(lineTxt.split("\":")[1].split(",\"")[0]);
					capital = Double.valueOf(lineTxt.split("\":")[2].split(",\"")[0]);
					capitalShadow = Double.valueOf(lineTxt.split("\":")[3].split(",\"")[0]);
					switch(tradeHands){
						case 0: curPosition = POSITION_INIT; break;
						case 1: curPosition = POSITION_BUY_LIT; break;
						case 2: curPosition = POSITION_BUY_MID; break;
						case 3: curPosition = POSITION_BUY_HAV; break;
						case -1: curPosition = POSITION_SEL_LIT; break;
						case -2: curPosition = POSITION_SEL_MID; break;
						case -3: curPosition = POSITION_SEL_HAV; break;
					}
				}
				read.close();
			} else {
				System.out.println("找不到指定的文件");
			}
		} catch (Exception e) {
			System.out.println("读取文件内容出错");
			e.printStackTrace();
		}
	}
	
	public static void refreshBehaviors(){
		String dataStr = "\"tradeHands\":"+tradeHands+",\"capital\":" + formatDouble(capital)+",\"capitalShadow\":" + capitalShadow;
		System.out.println(dataStr);
		try {
			OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("data.txt"));  
			osw.write(dataStr,0, dataStr.length());
			osw.flush();
			osw.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}  
		
	}
	public static void getWhatToDo(int position){
		if(position == curPosition){
			return;
		}
		switch(position){
			case POSITION_INIT: 
				switch(curPosition){
					case POSITION_INIT: break;
					case POSITION_BUY_HAV: selFree(POSITION_BUY_HAV); break;
					case POSITION_BUY_LIT: selFree(POSITION_BUY_LIT); break;
					case POSITION_BUY_MID: selFree(POSITION_BUY_MID); break;
					case POSITION_SEL_HAV: buyFree(POSITION_SEL_HAV); break;
					case POSITION_SEL_LIT: buyFree(POSITION_SEL_LIT); break;
					case POSITION_SEL_MID: buyFree(POSITION_SEL_MID); break;
					default: break;
				}break;
			case POSITION_BUY_HAV: 
				switch(curPosition){
				case POSITION_INIT: buyOpen(POSITION_BUY_HAV); break;
				case POSITION_BUY_HAV: break;
				case POSITION_BUY_LIT: buyOpen(POSITION_BUY_MID); break;
				case POSITION_BUY_MID: buyOpen(POSITION_BUY_LIT); break;
				case POSITION_SEL_HAV: buyFree(POSITION_SEL_HAV); buyOpen(POSITION_BUY_HAV); break;
				case POSITION_SEL_LIT: buyFree(POSITION_SEL_LIT); buyOpen(POSITION_BUY_HAV); break;
				case POSITION_SEL_MID: buyFree(POSITION_SEL_MID); buyOpen(POSITION_BUY_HAV); break;
				default: break;
			}break;
			case POSITION_BUY_LIT: 
				switch(curPosition){
				case POSITION_INIT: buyOpen(POSITION_BUY_LIT); break;
				case POSITION_BUY_HAV: selFree(POSITION_BUY_MID); break;
				case POSITION_BUY_LIT: break;
				case POSITION_BUY_MID: selFree(POSITION_BUY_LIT); break;
				case POSITION_SEL_HAV: buyFree(POSITION_SEL_HAV); buyOpen(POSITION_BUY_LIT); break;
				case POSITION_SEL_LIT: buyFree(POSITION_SEL_LIT); buyOpen(POSITION_BUY_LIT); break;
				case POSITION_SEL_MID: buyFree(POSITION_SEL_MID); buyOpen(POSITION_BUY_LIT); break;
				default: break;
			}break;
			case POSITION_BUY_MID: 
				switch(curPosition){
				case POSITION_INIT: buyOpen(POSITION_BUY_MID); break;
				case POSITION_BUY_HAV: selFree(POSITION_BUY_LIT); break;
				case POSITION_BUY_LIT: buyOpen(POSITION_BUY_LIT); break;
				case POSITION_BUY_MID: break;
				case POSITION_SEL_HAV: buyFree(POSITION_SEL_HAV); buyOpen(POSITION_BUY_MID); break;
				case POSITION_SEL_LIT: buyFree(POSITION_SEL_LIT); buyOpen(POSITION_BUY_MID); break;
				case POSITION_SEL_MID: buyFree(POSITION_SEL_MID); buyOpen(POSITION_BUY_MID); break;
				default: break;
			}break;
			case POSITION_SEL_HAV: 
				switch(curPosition){
				case POSITION_INIT: selOpen(POSITION_SEL_HAV); break;
				case POSITION_BUY_HAV: selFree(POSITION_BUY_HAV); selOpen(POSITION_SEL_HAV); break;
				case POSITION_BUY_LIT: selFree(POSITION_BUY_LIT); selOpen(POSITION_SEL_HAV); break;
				case POSITION_BUY_MID: selFree(POSITION_BUY_MID); selOpen(POSITION_SEL_HAV); break;
				case POSITION_SEL_HAV: break;
				case POSITION_SEL_LIT: selOpen(POSITION_SEL_MID); break;
				case POSITION_SEL_MID: selOpen(POSITION_SEL_LIT); break;
				default: break;
			}break;
			case POSITION_SEL_LIT: 
				switch(curPosition){
				case POSITION_INIT: selOpen(POSITION_SEL_LIT); break;
				case POSITION_BUY_HAV: selFree(POSITION_BUY_HAV); selOpen(POSITION_SEL_LIT); break;
				case POSITION_BUY_LIT: selFree(POSITION_BUY_LIT); selOpen(POSITION_SEL_LIT); break;
				case POSITION_BUY_MID: selFree(POSITION_BUY_MID); selOpen(POSITION_SEL_LIT); break;
				case POSITION_SEL_HAV: buyFree(POSITION_BUY_MID); break;
				case POSITION_SEL_LIT: break;
				case POSITION_SEL_MID: buyFree(POSITION_BUY_LIT); break;
				default: break;
			}break;
			case POSITION_SEL_MID: 
				switch(curPosition){
				case POSITION_INIT: selOpen(POSITION_SEL_MID); break;
				case POSITION_BUY_HAV: selFree(POSITION_BUY_HAV); selOpen(POSITION_SEL_MID); break;
				case POSITION_BUY_LIT: selFree(POSITION_BUY_LIT); selOpen(POSITION_SEL_MID); break;
				case POSITION_BUY_MID: selFree(POSITION_BUY_MID); selOpen(POSITION_SEL_MID); break;
				case POSITION_SEL_HAV: buyFree(POSITION_BUY_LIT); break;
				case POSITION_SEL_LIT: selOpen(POSITION_SEL_LIT); break;
				case POSITION_SEL_MID: break;
				default: break;
			}break;
			default: break;
		}
		curPosition = position;
	}
	
	public static boolean isTriRise(){//连续三日纯涨
		if(platinList.size() < 3){
			return false;
		}
			
		for (int i = 0; i < 3; i++) {
			if((Double)platinList.get(platinList.size()-1-i).get("open") - (Double)platinList.get(platinList.size()-1-i).get("close") >= 0){
				return false;
			}
		}
		return true;
	}
	
	public static boolean isTwiFall(){
		if(platinList.size() < 3){
			return false;
		}
			
		for (int i = 0; i < 2; i++) {
			if((Double)platinList.get(platinList.size()-1-i).get("open") - (Double)platinList.get(platinList.size()-1-i).get("close") <= 0){
				return false;
			}
		}
		return true;
	}
	
	public static boolean isTwiTriUpAvgTwn(){//前三日有最起码两日突破廿日线，且最近一日穿插廿日线
		if(platinList.size() < 3){
			return false;
		}
		if((Double)platinList.get(platinList.size() - 1).get("high") - (Double)platinList.get(platinList.size() - 1).get("TWENDAYAVG") > 0){
			if((Double)platinList.get(platinList.size() - 2).get("high") - (Double)platinList.get(platinList.size() - 2).get("TWENDAYAVG") > 0){
				return true;
			}
			if((Double)platinList.get(platinList.size() - 3).get("high") - (Double)platinList.get(platinList.size() - 3).get("TWENDAYAVG") > 0){
				return true;
			}
		}
		return false;
	}
	
	public static boolean isObveTwnAvg(){//前两日均收于廿日线上方
		if(platinList.size() < 3){
			return false;
		}
		if((Double)platinList.get(platinList.size() - 1).get("close") - (Double)platinList.get(platinList.size() - 1).get("TWENDAYAVG") > 0
				&& (Double)platinList.get(platinList.size() - 2).get("close") - (Double)platinList.get(platinList.size() - 2).get("TWENDAYAVG") > 0){
			return true;
		}
		return false;
	}
	
	public static void buyOpen(int units){
		tradeHands += Math.abs(units);
		capital -= Math.abs(units*1000)*silverNewPrice;
		System.out.println("capital---"+capital);
		String newOrder = "买入开仓："+Math.abs(units)+"手，价格："+formatDouble(silverNewPrice)+"，目前持仓"+tradeHands+"手。";
		orderList.add(newOrder);
	}
	
	public static void buyFree(int units){
		tradeHands += Math.abs(units);
		capital -= Math.abs(units*1000)*silverNewPrice;
		System.out.println("capital---"+capital);
		String newOrder = "买入平仓："+Math.abs(units)+"手，价格："+formatDouble(silverNewPrice)+"，目前持仓"+tradeHands+"手。";
		if(tradeHands == 0){
			newOrder += "浮动盈亏："+ formatDouble(capital -capitalShadow);
		}
		orderList.add(newOrder);
	}
	
	public static void selOpen(int units){
		tradeHands -= Math.abs(units);
		capital += Math.abs(units*1000)*silverNewPrice;
		System.out.println("capital---"+capital);
		String newOrder = "卖出开仓："+Math.abs(units)+"手，价格："+formatDouble(silverNewPrice)+"，目前持仓"+tradeHands+"手。";
		orderList.add(newOrder);
	}
	
	public static void selFree(int units){
		tradeHands -= Math.abs(units);
		capital += Math.abs(units*1000)*silverNewPrice;
		System.out.println("capital---"+capital);
		String newOrder = "卖出平仓："+Math.abs(units)+"手，价格："+formatDouble(silverNewPrice)+"，目前持仓"+tradeHands+"手。";
		if(tradeHands == 0){
			newOrder += "浮动盈亏："+ formatDouble(capital -capitalShadow);
		}
		orderList.add(newOrder);
	}
	
	public static double formatDouble(Double value){
		return Math.round(value*10000)/10000.0000;
	}
	
	public static void informBoss(){
		Mailer mailer = new Mailer();
		String subject = "策略：";
		for (String content : orderList) {
			System.out.println(content);
			for (String address : Constant.emailListBoss) {
				try {
					if (!isDebug) {
						mailer.sendMail(address, subject, content);
					}
				} catch (Exception e) {
					// TODO: handle exception
					e.printStackTrace();
				}
			}
		}
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		isDebug = true;
		initDayAvgPrices();
		List<Map<String, Object>> platinListShadow = platinList;
		for (int i = observeDateNum; i < platinListShadow.size(); i++) {
			if(i == platinListShadow.size() - 1){
				silverNewPrice = (Double)silverList.get(i).get("close");
			}else{
				silverNewPrice = ((Double)silverList.get(i+1).get("open")*0.8 + (Double)silverList.get(i+1).get("close")*0.2);
			}
			platinList = platinListShadow.subList(0, i);
			getStrategy();
		}
	}
}
